package main

import (
	"context"
	"io"
	"os"
	"sync"

	pb "go-kit-service/api/video"

	"github.com/sirupsen/logrus"
	"google.golang.org/grpc"
)

const (
	GRPCAddr   = "192.168.1.100:9000"
	VideoDir   = "./client/videos"
	ChunckSize = 1 << 20
)

type GRPCClient struct {
	client pb.VideoClient
	thread int
	count  int
	wg     *sync.WaitGroup
}

func main() {
	c := NewGRPCClient()
	// c.TestVideoList()
	// c.TestUploadVideo()
	// c.TestDownloadVideo()
	c.TestConvertVideo()
}

func NewGRPCClient() *GRPCClient {
	conn, err := grpc.Dial(GRPCAddr, grpc.WithInsecure(), grpc.WithBlock())
	if err != nil {
		panic("create grpc client error: " + err.Error())
	}

	client := pb.NewVideoClient(conn)

	return &GRPCClient{
		client: client,
		thread: 1,
		count:  1,
		wg:     &sync.WaitGroup{},
	}
}

func (c *GRPCClient) TestVideoList() {
	resp, err := c.client.VideoList(context.Background(), &pb.VideoListRequest{})
	if err != nil {
		logrus.Errorf("grpc test VideoList error: %v\n", err)
		return
	}

	for _, info := range resp.GetVideoList() {
		logrus.Infof("video name: %s, size: %d\n", info.GetName(), info.GetSize())
	}
}

func (c *GRPCClient) TestUploadVideo() {
	files, err := os.ReadDir(VideoDir)
	if err != nil {
		logrus.Errorf("read video dir error: %v", err)
		return
	}

	for _, file := range files {
		filepath := VideoDir + "/" + file.Name()
		f, err := os.Open(filepath)
		if err != nil {
			logrus.Errorf("open file error: %v", err)
			return
		}

		client, err := c.client.UploadVideo(context.Background())
		if err != nil {
			logrus.Errorf("grpc upload video error: %v", err)
			return
		}

		temp := make([]byte, ChunckSize, ChunckSize)
		for {
			n, err := f.Read(temp)
			if err != nil {
				if err == io.EOF {
					logrus.Infof("video file: %s read finish", filepath)
					break
				}
				logrus.Errorf("read file: %s, error: %v", filepath, err)
				break
			}

			err = client.Send(&pb.UploadVideoRequest{Name: file.Name(), Data: temp[:n]})
			if err != nil {
				logrus.Errorf("grpc send upload video info error: %v", err)
				break
			}
		}

		f.Close()

		_, err = client.CloseAndRecv()
		if err != nil {
			logrus.Errorf("error: %v", err)
		}
	}
}

func (c *GRPCClient) TestDownloadVideo() {
	videoName := "EE-bNr36nyA.mp4"
	client, err := c.client.DownloadVideo(context.Background(), &pb.DownloadVideoRequest{Name: videoName})
	if err != nil {
		logrus.Errorf("grpc send download video error: %v", err)
		return
	}

	f, err := os.OpenFile(VideoDir+"/download.mp4", os.O_CREATE|os.O_RDWR|os.O_APPEND, 0777)
	if err != nil {
		logrus.Errorf("open download video file error: %v", err)
		return
	}

	for {
		resp, err := client.Recv()
		if err != nil {
			if err == io.EOF {
				break
			}

			logrus.Errorf("download video recv error: %v", err)
			break
		}

		f.Write(resp.Data)
	}

	f.Close()
}

func (c *GRPCClient) TestConvertVideo() {
	videoPath := VideoDir + "/download.mp4"
	newVideoPath := VideoDir + "/new-download.mp4"
	client, err := c.client.ConvertVideo(context.Background())
	if err != nil {
		logrus.Errorf("get convert video client error: %v", err)
		return
	}

	f, err := os.Open(videoPath)
	if err != nil {
		logrus.Errorf("open video file error: %v", err)
		return
	}
	defer f.Close()

	newFile, err := os.OpenFile(newVideoPath, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0777)
	if err != nil {
		logrus.Errorf("open new video file error: %v", err)
		return
	}
	defer newFile.Close()

	temp := make([]byte, ChunckSize, ChunckSize)
	for {
		n, err := f.Read(temp)
		if err != nil {
			if err == io.EOF {
				break
			}

			logrus.Errorf("video file read error: %v", err)
			return
		}

		if err = client.Send(&pb.ConvertVideoRequest{Data: temp[:n]}); err != nil {
			logrus.Errorf("grpc server send request error: %v", err)
			return
		}

		resp, err := client.Recv()
		if err != nil {
			logrus.Errorf("grpc server recv response error: %v", err)
			return
		}

		newFile.Write(resp.Data)
	}
}
